package service

import (
	"bufio"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"os"
	"path/filepath"
	"strings"
	"time"
	"wms/internal/model"
	"wms/internal/model/request"
	"wms/internal/model/response"
	"wms/pkg/global"
	"wms/pkg/logger"

	"go.uber.org/zap"
)

// LogService 日志服务
type LogService struct {
	logDir string
}

// LogEntry 日志条目
type LogEntry struct {
	Time      time.Time `json:"time"`      // 时间
	Level     string    `json:"level"`     // 日志级别
	Message   string    `json:"message"`   // 日志内容
	Caller    string    `json:"caller"`    // 调用文件
	UserID    uint      `json:"user_id"`   // 用户ID
	Operation string    `json:"operation"` // 操作类型
}

// LogListResult 日志列表结果
type LogListResult struct {
	Logs  []LogEntry `json:"logs"`  // 日志条目
	Total int        `json:"total"` // 总条数
}

// NewLogService 创建日志服务
func NewLogService() *LogService {
	return &LogService{
		logDir: "logs",
	}
}

// GetLogs 获取系统日志
func (s *LogService) GetLogs(req request.LogListRequest) ([]response.LogResponse, int64, error) {
	logger.Info("获取日志列表请求", zap.Any("req", req))

	var logs []model.OperationLog
	var total int64

	// 设置默认分页参数
	if req.Page <= 0 {
		req.Page = 1
	}
	if req.PageSize <= 0 {
		req.PageSize = 10
	}

	// 使用全局DB实例
	db := global.DB.Model(&model.OperationLog{})

	// 添加筛选条件
	if req.Type != "" {
		db = db.Where("action = ?", req.Type)
	}

	if req.Keyword != "" {
		db = db.Where("username LIKE ? OR module LIKE ? OR path LIKE ? OR request_data LIKE ?",
			"%"+req.Keyword+"%", "%"+req.Keyword+"%", "%"+req.Keyword+"%", "%"+req.Keyword+"%")
	}

	// 处理日期范围
	if len(req.DateRange) == 2 && req.DateRange[0] != "" && req.DateRange[1] != "" {
		db = db.Where("created_at BETWEEN ? AND ?", req.DateRange[0], req.DateRange[1])
	}

	// 获取总数
	err := db.Count(&total).Error
	if err != nil {
		logger.Error("获取日志总数失败", zap.Error(err))
		return nil, 0, err
	}

	// 分页查询
	offset := (req.Page - 1) * req.PageSize
	err = db.Order("created_at DESC").Offset(offset).Limit(req.PageSize).Find(&logs).Error

	if err != nil {
		logger.Error("查询日志列表失败", zap.Error(err))
		return nil, 0, err
	}

	// 没有查询到数据时返回空数组和总数为0
	if len(logs) == 0 {
		logger.Info("未查询到日志数据")
		return []response.LogResponse{}, 0, nil
	}

	logger.Info("查询到日志数据", zap.Int("count", len(logs)))

	// 转换为响应格式
	var logResponses []response.LogResponse
	for _, log := range logs {
		logResponses = append(logResponses, response.LogResponse{
			ID:           log.ID,
			UserID:       log.UserID,
			Username:     log.Username,
			IP:           log.IP,
			Method:       log.Method,
			Path:         log.Path,
			Status:       log.Status,
			Type:         log.Action,
			Latency:      log.Duration,
			Agent:        "",
			ErrorMsg:     log.Error,
			RequestBody:  log.RequestData,
			ResponseBody: log.Response,
			CreatedAt:    log.CreatedAt,
		})
	}

	return logResponses, total, nil
}

// GetLogTypes 获取日志类型
func (s *LogService) GetLogTypes() []string {
	// 查询数据库中存在的操作类型
	var actionTypes []string
	err := global.DB.Model(&model.OperationLog{}).Distinct().Pluck("action", &actionTypes).Error
	if err != nil {
		logger.Error("查询日志类型失败", zap.Error(err))
		// 返回默认日志类型
		return []string{
			"查询",
			"创建",
			"更新",
			"删除",
			"导出",
			"导入",
			"登录",
			"退出",
		}
	}

	// 如果数据库中没有类型，则使用默认类型
	if len(actionTypes) == 0 {
		return []string{
			"查询",
			"创建",
			"更新",
			"删除",
			"导出",
			"导入",
			"登录",
			"退出",
		}
	}

	return actionTypes
}

// GetLogsFromFile 从文件中获取日志（原先的GetLogs方法改名）
func (s *LogService) GetLogsFromFile(page, pageSize int, level, keyword string, startTime, endTime time.Time) (*LogListResult, error) {
	// 确保日志目录存在
	if err := s.ensureLogDir(); err != nil {
		return nil, err
	}

	// 日志文件路径
	logFile := filepath.Join(s.logDir, "wms.log")
	if _, err := os.Stat(logFile); os.IsNotExist(err) {
		return &LogListResult{
			Logs:  []LogEntry{},
			Total: 0,
		}, nil
	}

	// 打开日志文件
	file, err := os.Open(logFile)
	if err != nil {
		return nil, err
	}
	defer file.Close()

	// 读取日志内容
	reader := bufio.NewReader(file)
	var allLogs []LogEntry
	var lineCount int

	for {
		line, err := reader.ReadString('\n')
		if err != nil {
			if err == io.EOF {
				break
			}
			return nil, err
		}

		lineCount++
		entry, err := s.parseLogLine(line)
		if err != nil {
			continue
		}

		// 仅保留业务操作日志
		if !s.isBusinessLog(entry) {
			continue
		}

		// 过滤条件
		if level != "" && !strings.EqualFold(entry.Level, level) {
			continue
		}

		if keyword != "" && !strings.Contains(strings.ToLower(entry.Message), strings.ToLower(keyword)) {
			continue
		}

		if !startTime.IsZero() && entry.Time.Before(startTime) {
			continue
		}

		if !endTime.IsZero() && entry.Time.After(endTime) {
			continue
		}

		allLogs = append(allLogs, entry)
	}

	// 分页处理
	total := len(allLogs)
	var logs []LogEntry

	// 计算起始索引和结束索引
	startIndex := (page - 1) * pageSize
	endIndex := startIndex + pageSize

	if startIndex < total {
		if endIndex > total {
			endIndex = total
		}
		logs = allLogs[startIndex:endIndex]
	}

	return &LogListResult{
		Logs:  logs,
		Total: total,
	}, nil
}

// parseLogLine 解析日志行
func (s *LogService) parseLogLine(line string) (LogEntry, error) {
	var entry LogEntry

	// 检查是否为JSON格式
	if strings.HasPrefix(line, "{") && strings.HasSuffix(strings.TrimSpace(line), "}") {
		// JSON格式日志解析
		var jsonLog struct {
			Level     string `json:"level"`
			Time      string `json:"time"`
			Caller    string `json:"caller"`
			Msg       string `json:"msg"`
			UserID    uint   `json:"user_id"`
			Operation string `json:"type"`
			Details   string `json:"details"`
		}

		if err := json.Unmarshal([]byte(line), &jsonLog); err != nil {
			return entry, err
		}

		// 解析时间
		t, err := time.Parse("2006-01-02 15:04:05", jsonLog.Time)
		if err != nil {
			// 尝试其他时间格式
			t, err = time.Parse(time.RFC3339, jsonLog.Time)
			if err != nil {
				// 使用当前时间作为备选
				t = time.Now()
			}
		}

		entry.Time = t
		entry.Level = strings.ToUpper(jsonLog.Level)
		entry.Message = jsonLog.Msg
		if jsonLog.Details != "" {
			entry.Message += " - " + jsonLog.Details
		}
		entry.Caller = jsonLog.Caller
		entry.UserID = jsonLog.UserID
		entry.Operation = jsonLog.Operation

		return entry, nil
	}

	// 如果不是JSON格式，使用旧的文本格式解析方式（保留原有逻辑作为后备）
	parts := strings.Split(line, " ")
	if len(parts) < 3 {
		return entry, errors.New("invalid log format")
	}

	// 解析时间
	timeStr := parts[0]
	t, err := time.Parse(time.RFC3339, timeStr)
	if err != nil {
		return entry, err
	}
	entry.Time = t

	// 解析级别
	entry.Level = parts[1]

	// 解析消息
	// 消息可能包含空格，需要找到caller的位置
	var message []string
	var callerIndex int
	for i := 2; i < len(parts); i++ {
		if strings.HasPrefix(parts[i], "caller=") {
			callerIndex = i
			break
		}
		message = append(message, parts[i])
	}
	entry.Message = strings.Join(message, " ")

	// 如果找到caller，则解析后续字段
	if callerIndex > 0 && callerIndex < len(parts) {
		// 解析caller
		callerParts := strings.Split(parts[callerIndex], "=")
		if len(callerParts) == 2 {
			entry.Caller = callerParts[1]
		}

		// 尝试解析user_id
		for i := callerIndex + 1; i < len(parts); i++ {
			if strings.HasPrefix(parts[i], "user_id=") {
				userIDStr := strings.TrimPrefix(parts[i], "user_id=")
				var userID uint
				if _, err := fmt.Sscanf(userIDStr, "%d", &userID); err == nil {
					entry.UserID = userID
				}
			} else if strings.HasPrefix(parts[i], "operation=") {
				entry.Operation = strings.TrimPrefix(parts[i], "operation=")
			}
		}
	}

	return entry, nil
}

// ensureLogDir 确保日志目录存在
func (s *LogService) ensureLogDir() error {
	if _, err := os.Stat(s.logDir); os.IsNotExist(err) {
		return os.MkdirAll(s.logDir, 0755)
	}
	return nil
}

// isBusinessLog 判断是否为业务操作日志
func (s *LogService) isBusinessLog(entry LogEntry) bool {
	// 如果有明确的操作类型，则认为是业务日志
	if entry.Operation != "" && entry.Operation != "system" {
		return true
	}

	// 排除JWT认证相关日志
	if strings.Contains(entry.Message, "JWT") ||
		strings.Contains(entry.Message, "Authorization") ||
		strings.Contains(entry.Message, "Bearer") {
		return false
	}

	// 排除数据库连接日志
	if strings.Contains(entry.Message, "数据库连接") ||
		strings.Contains(entry.Message, "迁移") {
		return false
	}

	// 排除菜单初始化日志
	if strings.Contains(entry.Message, "菜单已存在") ||
		strings.Contains(entry.Message, "初始化菜单") {
		return false
	}

	// 检查关键词，识别业务操作日志
	businessKeywords := []string{
		"登录", "退出", "创建", "更新", "删除", "入库", "出库",
		"收货", "上架", "拣货", "发货", "盘点", "调整", "审核",
		"approved", "rejected", "login", "logout", "created",
		"updated", "deleted", "inbound", "outbound", "receive",
		"putaway", "pick", "ship", "inventory", "adjust", "audit",
	}

	lowerMsg := strings.ToLower(entry.Message)
	for _, keyword := range businessKeywords {
		if strings.Contains(lowerMsg, strings.ToLower(keyword)) {
			return true
		}
	}

	// 筛选出用户相关操作
	if entry.UserID > 0 {
		// 用户ID大于0表示该操作由特定用户执行
		return true
	}

	return false
}
